package server

import (
	"context"
	"errors"
	"fmt"
	"k8s-gpu-collector/pkg/config"
	"k8s-gpu-collector/pkg/k8s"
	"k8s-gpu-collector/pkg/service"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"k8s.io/client-go/kubernetes"
)

type Server struct {
	Port int

	engine *gin.Engine
	cs     *kubernetes.Clientset
}

func NewServer(cfg *config.Config) (*Server, error) {

	server := gin.New()
	server.Use(gin.Recovery())
	registerRoutes(server)

	cs, err := k8s.NewClientSet(cfg.InCluster, cfg.KubeconfigFile)
	if err != nil {
		logrus.Errorf("[NewServer] - failed to create k8s clientset: %v", err)
		return nil, err
	}
	return &Server{
		engine: server,
		Port:   cfg.Port,
		cs:     cs,
	}, nil
}

func registerRoutes(e *gin.Engine) {
	e.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"status": "ok",
		})
	})

	e.GET("metric", service.GPUMetric)
}

func (s *Server) Run() error {
	ports := strconv.Itoa(s.Port)
	addr := fmt.Sprintf(":%d", s.Port)
	srv := &http.Server{
		Addr:    addr,
		Handler: s.engine,
	}
	logrus.Infof("[main] - Starting server on port: %s", ports)
	go func() {
		if err := srv.ListenAndServe(); err != nil {
			if errors.Is(err, http.ErrServerClosed) {
				logrus.Infof("[Run] - Server closed")
				return
			}
			logrus.Errorf("[Run] - failed to start server: %v", err)
		}
	}()

	stopCh := make(chan os.Signal, 1)

	signal.Notify(stopCh, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

	<-stopCh
	timeoutCtx, cancelFunc := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancelFunc()

	if err := srv.Shutdown(timeoutCtx); err != nil {
		logrus.Errorf("[Run] - failed to shutdown server: %v", err)
		return err
	}
	return nil
}
